/*
 * Copyright (C) 2003-2014  Pascal Essiembre
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.essiembre.eclipse.rbe.ui.preferences;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import com.essiembre.eclipse.rbe.RBEPlugin;
import com.essiembre.eclipse.rbe.model.workbench.RBEPreferences;

/**
 * Plugin preference page.
 * @author Pascal Essiembre
 */
public class RBEFormattingPrefPage extends AbstractRBEPrefPage {
    
    /* Preference fields. */
    private Button showGeneratedBy;

    private Button convertUnicodeToEncoded;
    private Button convertUnicodeUpperCase;

    private Button alignEqualSigns;
    private Button ensureSpacesAroundEquals;
    
    private Button groupKeys;
    private Text groupLevelDeep;
    private Text groupLineBreaks;
    private Button groupAlignEqualSigns;
    
    private Button wrapLines;
    private Text wrapCharLimit;
    private Button wrapAlignEqualSigns;
    private Text wrapIndentSpaces;
    private Button wrapNewLine;
    
    private Button newLineTypeForce;
    private Button[] newLineTypes = new Button[3];

    private Button keepEmptyFields;
    
    /**
     * Constructor.
     */
    public RBEFormattingPrefPage() {
        super();
    }

    @Override
    protected Control createContents(Composite parent) {
        IPreferenceStore prefs = getPreferenceStore();
        Composite field = null;
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new GridLayout(1, false));
        
        // Show generated by comment?
        field = createFieldComposite(composite);
        showGeneratedBy = new Button(field, SWT.CHECK);
        showGeneratedBy.setSelection(
                prefs.getBoolean(RBEPreferences.SHOW_GENERATOR));
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.showGeneratedBy"));

        // Convert unicode to encoded?
        field = createFieldComposite(composite);
        convertUnicodeToEncoded = new Button(field, SWT.CHECK);
        convertUnicodeToEncoded.setSelection(
                prefs.getBoolean(RBEPreferences.CONVERT_UNICODE_TO_ENCODED));
        convertUnicodeToEncoded.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                refreshEnabledStatuses();
            }
        });
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.convertUnicode"));

        // Use upper case for encoded hexadecimal values?
        field = createFieldComposite(composite, indentPixels);
        convertUnicodeUpperCase = new Button(field, SWT.CHECK);
        convertUnicodeUpperCase.setSelection(prefs.getBoolean(
                RBEPreferences.CONVERT_UNICODE_TO_ENCODED_UPPER));
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.convertUnicode.upper"));
        
        // Align equal signs?
        field = createFieldComposite(composite);
        alignEqualSigns = new Button(field, SWT.CHECK);
        alignEqualSigns.setSelection(
                prefs.getBoolean(RBEPreferences.ALIGN_EQUAL_SIGNS));
        alignEqualSigns.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                refreshEnabledStatuses();
            }
        });
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.alignEquals"));

        field = createFieldComposite(composite);
        ensureSpacesAroundEquals = new Button(field, SWT.CHECK);
        ensureSpacesAroundEquals.setSelection(
                prefs.getBoolean(RBEPreferences.SPACES_AROUND_EQUAL_SIGNS));
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.spacesAroundEquals"));
        
        // Group keys?
        field = createFieldComposite(composite);
        groupKeys = new Button(field, SWT.CHECK);
        groupKeys.setSelection(prefs.getBoolean(RBEPreferences.GROUP_KEYS));
        groupKeys.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                refreshEnabledStatuses();
            }
        });
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.groupKeys"));

        // Group keys by how many level deep?
        field = createFieldComposite(composite, indentPixels);
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.levelDeep"));
        groupLevelDeep = new Text(field, SWT.BORDER);
        groupLevelDeep.setText(prefs.getString(
                RBEPreferences.GROUP_LEVEL_DEPTH));
        groupLevelDeep.setTextLimit(2);
        setWidthInChars(groupLevelDeep, 2);
        groupLevelDeep.addKeyListener(new IntTextValidatorKeyListener(
                RBEPlugin.getString(
                        "prefs.levelDeep.error")));
        
        // How many lines between groups?
        field = createFieldComposite(composite, indentPixels);
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.linesBetween"));
        groupLineBreaks = new Text(field, SWT.BORDER);
        groupLineBreaks.setText(
                prefs.getString(RBEPreferences.GROUP_LINE_BREAKS));
        groupLineBreaks.setTextLimit(2);
        setWidthInChars(groupLineBreaks, 2);
        groupLineBreaks.addKeyListener(new IntTextValidatorKeyListener(
                RBEPlugin.getString(
                        "prefs.linesBetween.error")));

        // Align equal signs within groups?
        field = createFieldComposite(composite, indentPixels);
        groupAlignEqualSigns = new Button(field, SWT.CHECK);
        groupAlignEqualSigns.setSelection(
                prefs.getBoolean(RBEPreferences.GROUP_ALIGN_EQUAL_SIGNS));
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString(
                        "prefs.groupAlignEquals"));

        // Wrap lines?
        field = createFieldComposite(composite);
        wrapLines = new Button(field, SWT.CHECK);
        wrapLines.setSelection(prefs.getBoolean(RBEPreferences.WRAP_LINES));
        wrapLines.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                refreshEnabledStatuses();
            }
        });
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.wrapLines"));
        
        // After how many characters should we wrap?
        field = createFieldComposite(composite, indentPixels);
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.wrapLinesChar"));
        wrapCharLimit = new Text(field, SWT.BORDER);
        wrapCharLimit.setText(prefs.getString(RBEPreferences.WRAP_CHAR_LIMIT));
        wrapCharLimit.setTextLimit(4);
        setWidthInChars(wrapCharLimit, 4);
        wrapCharLimit.addKeyListener(new IntTextValidatorKeyListener(
                RBEPlugin.getString(
                        "prefs.wrapLinesChar.error")));
        
        // Align wrapped lines with equal signs?
        field = createFieldComposite(composite, indentPixels);
        wrapAlignEqualSigns = new Button(field, SWT.CHECK);
        wrapAlignEqualSigns.setSelection(
                prefs.getBoolean(RBEPreferences.WRAP_ALIGN_EQUAL_SIGNS));
        wrapAlignEqualSigns.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                refreshEnabledStatuses();
            }
        });
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.wrapAlignEquals"));

        // How many spaces/tabs to use for indenting?
        field = createFieldComposite(composite, indentPixels);
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.wrapIndent"));
        wrapIndentSpaces = new Text(field, SWT.BORDER);
        wrapIndentSpaces.setText(
                prefs.getString(RBEPreferences.WRAP_INDENT_SPACES));
        wrapIndentSpaces.setTextLimit(2);
        setWidthInChars(wrapIndentSpaces, 2);
        wrapIndentSpaces.addKeyListener(new IntTextValidatorKeyListener(
                RBEPlugin.getString(
                        "prefs.wrapIndent.error")));

        // Should we wrap after new line characters
        field = createFieldComposite(composite);
        wrapNewLine = new Button(field, SWT.CHECK);
        wrapNewLine.setSelection(
                prefs.getBoolean(RBEPreferences.NEW_LINE_NICE));
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString(
                        "prefs.newline.nice"));

        // How should new lines appear in properties file
        field = createFieldComposite(composite);
        newLineTypeForce = new Button(field, SWT.CHECK);
        newLineTypeForce.setSelection(
                prefs.getBoolean(RBEPreferences.FORCE_NEW_LINE_TYPE));
        newLineTypeForce.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                refreshEnabledStatuses();
            }
        });
        Composite newLineRadioGroup = new Composite(field, SWT.NONE); 
        new Label(newLineRadioGroup, SWT.NONE).setText(
                RBEPlugin.getString(
                        "prefs.newline.force"));
        newLineRadioGroup.setLayout(new RowLayout());
        newLineTypes[RBEPreferences.NEW_LINE_UNIX] = 
                new Button(newLineRadioGroup, SWT.RADIO);
        newLineTypes[RBEPreferences.NEW_LINE_UNIX].setText(
                "UNIX (\\n)");
        newLineTypes[RBEPreferences.NEW_LINE_WIN] = 
                new Button(newLineRadioGroup, SWT.RADIO);
        newLineTypes[RBEPreferences.NEW_LINE_WIN].setText(
                "Windows (\\r\\n)");
        newLineTypes[RBEPreferences.NEW_LINE_MAC] =
                new Button(newLineRadioGroup, SWT.RADIO);
        newLineTypes[RBEPreferences.NEW_LINE_MAC].setText(
                "Mac (\\r)");
        newLineTypes[prefs.getInt(
                RBEPreferences.NEW_LINE_TYPE)].setSelection(true);
        
        // Keep empty fields?
        field = createFieldComposite(composite);
        keepEmptyFields = new Button(field, SWT.CHECK);
        keepEmptyFields.setSelection(prefs.getBoolean(
                RBEPreferences.KEEP_EMPTY_FIELDS));
        new Label(field, SWT.NONE).setText(
                RBEPlugin.getString("prefs.keepEmptyFields"));
        
        refreshEnabledStatuses();
        
        return composite;
    }


    @Override
    public boolean performOk() {
        IPreferenceStore prefs = getPreferenceStore();
        prefs.setValue(RBEPreferences.SHOW_GENERATOR,
                showGeneratedBy.getSelection());
        prefs.setValue(RBEPreferences.CONVERT_UNICODE_TO_ENCODED,
                convertUnicodeToEncoded.getSelection());
        prefs.setValue(RBEPreferences.CONVERT_UNICODE_TO_ENCODED_UPPER,
                convertUnicodeUpperCase.getSelection());
        prefs.setValue(RBEPreferences.ALIGN_EQUAL_SIGNS,
                alignEqualSigns.getSelection());
        prefs.setValue(RBEPreferences.SPACES_AROUND_EQUAL_SIGNS,
                ensureSpacesAroundEquals.getSelection());
        prefs.setValue(RBEPreferences.GROUP_KEYS,
                groupKeys.getSelection());
        prefs.setValue(RBEPreferences.GROUP_LEVEL_DEPTH,
                groupLevelDeep.getText());
        prefs.setValue(RBEPreferences.GROUP_LINE_BREAKS,
                groupLineBreaks.getText());
        prefs.setValue(RBEPreferences.GROUP_ALIGN_EQUAL_SIGNS,
                groupAlignEqualSigns.getSelection());
        prefs.setValue(RBEPreferences.WRAP_LINES,
                wrapLines.getSelection());
        prefs.setValue(RBEPreferences.WRAP_CHAR_LIMIT,
                wrapCharLimit.getText());
        prefs.setValue(RBEPreferences.WRAP_ALIGN_EQUAL_SIGNS,
                wrapAlignEqualSigns.getSelection());
        prefs.setValue(RBEPreferences.WRAP_INDENT_SPACES,
                wrapIndentSpaces.getText());
        prefs.setValue(RBEPreferences.NEW_LINE_NICE,
                wrapNewLine.getSelection());
        prefs.setValue(RBEPreferences.FORCE_NEW_LINE_TYPE,
                newLineTypeForce.getSelection());
        for (int i = 0; i < newLineTypes.length; i++) {
            if (newLineTypes[i].getSelection()) {
                prefs.setValue(RBEPreferences.NEW_LINE_TYPE, i);
            }
        }
        prefs.setValue(RBEPreferences.KEEP_EMPTY_FIELDS,
                keepEmptyFields.getSelection());
        refreshEnabledStatuses();
        return super.performOk();
    }
    

    @Override
    protected void performDefaults() {
        IPreferenceStore prefs = getPreferenceStore();
        showGeneratedBy.setSelection(prefs.getDefaultBoolean(
                RBEPreferences.SHOW_GENERATOR));
        convertUnicodeToEncoded.setSelection(prefs.getDefaultBoolean(
                RBEPreferences.CONVERT_UNICODE_TO_ENCODED));
        convertUnicodeToEncoded.setSelection(prefs.getDefaultBoolean(
                RBEPreferences.CONVERT_UNICODE_TO_ENCODED_UPPER));
        alignEqualSigns.setSelection(
                prefs.getDefaultBoolean(RBEPreferences.ALIGN_EQUAL_SIGNS));
        alignEqualSigns.setSelection(prefs.getDefaultBoolean(
                RBEPreferences.SPACES_AROUND_EQUAL_SIGNS));
        groupKeys.setSelection(
                prefs.getDefaultBoolean(RBEPreferences.GROUP_KEYS));
        groupLevelDeep.setText(
                prefs.getDefaultString(RBEPreferences.GROUP_LEVEL_DEPTH));
        groupLineBreaks.setText(
                prefs.getDefaultString(RBEPreferences.GROUP_LINE_BREAKS));
        groupAlignEqualSigns.setSelection(prefs.getDefaultBoolean(
                RBEPreferences.GROUP_ALIGN_EQUAL_SIGNS));
        wrapLines.setSelection(
                prefs.getDefaultBoolean(RBEPreferences.WRAP_LINES));
        wrapCharLimit.setText(
                prefs.getDefaultString(RBEPreferences.WRAP_CHAR_LIMIT));
        wrapAlignEqualSigns.setSelection(
                prefs.getDefaultBoolean(RBEPreferences.WRAP_ALIGN_EQUAL_SIGNS));
        wrapIndentSpaces.setText(
                prefs.getDefaultString(RBEPreferences.WRAP_INDENT_SPACES));
        wrapNewLine.setSelection(
                prefs.getDefaultBoolean(RBEPreferences.NEW_LINE_NICE));
        newLineTypeForce.setSelection(
                prefs.getDefaultBoolean(RBEPreferences.FORCE_NEW_LINE_TYPE));
        newLineTypes[prefs.getDefaultInt(
                RBEPreferences.NEW_LINE_TYPE)].setSelection(true);
        keepEmptyFields.setSelection(
                prefs.getDefaultBoolean(RBEPreferences.KEEP_EMPTY_FIELDS));
        refreshEnabledStatuses();
        super.performDefaults();
    }

    /*default*/ void refreshEnabledStatuses() {
        boolean isEncodingUnicode = convertUnicodeToEncoded.getSelection();
        boolean isGroupKeyEnabled = groupKeys.getSelection();
        boolean isAlignEqualsEnabled = alignEqualSigns.getSelection();
        boolean isWrapEnabled = wrapLines.getSelection();
        boolean isWrapAlignEqualsEnabled = wrapAlignEqualSigns.getSelection();
        boolean isNewLineStyleForced = newLineTypeForce.getSelection();

        convertUnicodeUpperCase.setEnabled(isEncodingUnicode);
        groupLevelDeep.setEnabled(isGroupKeyEnabled);
        groupLineBreaks.setEnabled(isGroupKeyEnabled);
        groupAlignEqualSigns.setEnabled(
                isGroupKeyEnabled && isAlignEqualsEnabled);
        wrapCharLimit.setEnabled(isWrapEnabled);
        wrapAlignEqualSigns.setEnabled(isWrapEnabled);
        wrapIndentSpaces.setEnabled(isWrapEnabled && !isWrapAlignEqualsEnabled);
        for (int i = 0; i < newLineTypes.length; i++) {
            newLineTypes[i].setEnabled(isNewLineStyleForced);
        }
    }
    
}
